/*
 * Copyright 2020-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.lettuce.core.api.coroutines

import io.lettuce.core.ExperimentalLettuceCoroutinesApi
import io.lettuce.core.ScanArgs
import io.lettuce.core.ScanCursor
import io.lettuce.core.ValueScanCursor
import kotlinx.coroutines.flow.Flow

/**
 * Coroutine executed commands for Sets.
 *
 * @param <K> Key type.
 * @param <V> Value type.
 * @author Mikhael Sokolov
 * @since 6.0
 * @generated by io.lettuce.apigenerator.CreateKotlinCoroutinesApi
 */
@ExperimentalLettuceCoroutinesApi
interface RedisSetCoroutinesCommands<K : Any, V : Any> {

    /**
     * Add one or more members to a set.
     *
     * @param key the key.
     * @param members the member type: value.
     * @return Long integer-reply the number of elements that were added to the set, not including all the elements already
     *         present into the set.
     */
    suspend fun sadd(key: K, vararg members: V): Long?

    /**
     * Get the number of members in a set.
     *
     * @param key the key.
     * @return Long integer-reply the cardinality (number of elements) of the set, or `false` if `key` does not
     *         exist.
     */
    suspend fun scard(key: K): Long?

    /**
     * Subtract multiple sets.
     *
     * @param keys the key.
     * @return Set<V> array-reply list with members of the resulting set.
     */
    fun sdiff(vararg keys: K): Flow<V>

    /**
     * Subtract multiple sets and store the resulting set in a key.
     *
     * @param destination the destination type: key.
     * @param keys the key.
     * @return Long integer-reply the number of elements in the resulting set.
     */
    suspend fun sdiffstore(destination: K, vararg keys: K): Long?

    /**
     * Intersect multiple sets.
     *
     * @param keys the key.
     * @return Set<V> array-reply list with members of the resulting set.
     */
    fun sinter(vararg keys: K): Flow<V>

    /**
     * Intersect multiple sets and store the resulting set in a key.
     *
     * @param destination the destination type: key.
     * @param keys the key.
     * @return Long integer-reply the number of elements in the resulting set.
     */
    suspend fun sinterstore(destination: K, vararg keys: K): Long?

    /**
     * Determine if a given value is a member of a set.
     *
     * @param key the key.
     * @param member the member type: value.
     * @return Boolean integer-reply specifically:
     *
     *         `true` if the element is a member of the set. `false` if the element is not a member of the set, or
     *         if `key` does not exist.
     */
    suspend fun sismember(key: K, member: V): Boolean?

    /**
     * Get all the members in a set.
     *
     * @param key the key.
     * @return Set<V> array-reply all elements of the set.
     */
    fun smembers(key: K): Flow<V>

    /**
     * Returns whether each member is a member of the set stored at key.
     *
     * @param key the key.
     * @param members the member type: value.
     * @return List<Boolean> array-reply list representing the membership of the given elements, in the same order as they
     *         are requested.
     * @since 6.1
     */
    fun smismember(key: K, vararg members: V): Flow<Boolean>

    /**
     * Move a member from one set to another.
     *
     * @param source the source key.
     * @param destination the destination type: key.
     * @param member the member type: value.
     * @return Boolean integer-reply specifically:
     *
     *         `true` if the element is moved. `false` if the element is not a member of `source` and no
     *         operation was performed.
     */
    suspend fun smove(source: K, destination: K, member: V): Boolean?

    /**
     * Remove and return a random member from a set.
     *
     * @param key the key.
     * @return V bulk-string-reply the removed element, or `null` when `key` does not exist.
     */
    suspend fun spop(key: K): V?

    /**
     * Remove and return one or multiple random members from a set.
     *
     * @param key the key.
     * @param count number of members to pop.
     * @return V bulk-string-reply the removed element, or `null` when `key` does not exist.
     */
    suspend fun spop(key: K, count: Long): Set<V>

    /**
     * Get one random member from a set.
     *
     * @param key the key.
     * @return V bulk-string-reply without the additional `count` argument the command returns a Bulk Reply with the
     *         randomly selected element, or `null` when `key` does not exist.
     */
    suspend fun srandmember(key: K): V?

    /**
     * Get one or multiple random members from a set.
     *
     * @param key the key.
     * @param count the count type: long.
     * @return Set<V> bulk-string-reply without the additional `count` argument the command returns a Bulk Reply
     *         with the randomly selected element, or `null` when `key` does not exist.
     */
    fun srandmember(key: K, count: Long): Flow<V>

    /**
     * Remove one or more members from a set.
     *
     * @param key the key.
     * @param members the member type: value.
     * @return Long integer-reply the number of members that were removed from the set, not including non existing members.
     */
    suspend fun srem(key: K, vararg members: V): Long?

    /**
     * Add multiple sets.
     *
     * @param keys the key.
     * @return Set<V> array-reply list with members of the resulting set.
     */
    fun sunion(vararg keys: K): Flow<V>

    /**
     * Add multiple sets and store the resulting set in a key.
     *
     * @param destination the destination type: key.
     * @param keys the key.
     * @return Long integer-reply the number of elements in the resulting set.
     */
    suspend fun sunionstore(destination: K, vararg keys: K): Long?

    /**
     * Incrementally iterate Set elements.
     *
     * @param key the key.
     * @return ValueScanCursor<V> scan cursor.
     */
    suspend fun sscan(key: K): ValueScanCursor<V>?

    /**
     * Incrementally iterate Set elements.
     *
     * @param key the key.
     * @param scanArgs scan arguments.
     * @return ValueScanCursor<V> scan cursor.
     */
    suspend fun sscan(key: K, scanArgs: ScanArgs): ValueScanCursor<V>?

    /**
     * Incrementally iterate Set elements.
     *
     * @param key the key.
     * @param scanCursor cursor to resume from a previous scan, must not be `null`.
     * @param scanArgs scan arguments.
     * @return ValueScanCursor<V> scan cursor.
     */
    suspend fun sscan(key: K, scanCursor: ScanCursor, scanArgs: ScanArgs): ValueScanCursor<V>?

    /**
     * Incrementally iterate Set elements.
     *
     * @param key the key.
     * @param scanCursor cursor to resume from a previous scan, must not be `null`.
     * @return ValueScanCursor<V> scan cursor.
     */
    suspend fun sscan(key: K, scanCursor: ScanCursor): ValueScanCursor<V>?

}

